using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Collections;

namespace Camalon.Drawing
{
	/// <summary>
	/// Summary description for VectorShape.
	/// </summary>
	[ToolboxItem( false)]
    [Designer("Camalon.Drawing.Design.VectorShapeDesigner, Camalon.Drawing.Design", typeof(IDesigner))]
    public abstract class VectorShape : Shape
	{
		[Browsable(false)]
		public event EventHandler PointsChanged	= null;

//		public VectorShape(System.ComponentModel.IContainer container):this()
//		{
//			///
//			/// Required for Windows.Forms Class Composition Designer support
//			///
//			container.Add(this);
//
//		}

		protected VectorShape( ):base()
		{
			base.MinSize=new Size(int.MinValue,int.MinValue);
			base.SetCanWarp( false );
			base.SetCanResize( false );//new
//			base.SetCanAnchor( false);
		}

		protected VectorShape( System.Drawing.Rectangle bounds):base(bounds)
		{
			base.MinSize=new Size(int.MinValue,int.MinValue);
			base.SetCanWarp( false );
			base.SetCanResize( false );//new
//			base.SetCanAnchor( false );
		}


		public override Outline Outline
		{
			get
			{
				return base.Outline;
			}
			set
			{
				base.Outline = value;
				SetCanWarp( value != null);
			}
		}


		private AnchorStyles _anchor = AnchorStyles.Top|AnchorStyles.Left;


		[Browsable(true)]
		[Category("Layout")]
		[DefaultValue(AnchorStyles.Top|AnchorStyles.Left)]
		public override AnchorStyles Anchor
		{
			get
			{
				if( this.Parent != null && this.Parent.ShouldScaleOnResize)// && this.Parent.ScalingResize) 
					return AnchorStyles.Top|AnchorStyles.Left;
			
				return _anchor;
			}
			set
			{
				if( !base.CanAnchor) return;

				if( _pathPoints == null) return;

				if( !AnchorPoint.ValidateAnchor( value )) return;

				if( value == _anchor) return;

				AnchorStyles oldValue= _anchor;
				ValueChangingEventArgs e = new ValueChangingEventArgs( _anchor, value);
				base.OnAnchorChanging( e );
				if( e.Cancel) return;

				_anchor = value;

				for ( int i = 0; i < _pathPoints.Length; i++)
				{
					AnchorPoint ap = _pathPoints[i];
					ap.Anchor = _anchor;
					_pathPoints[i] = ap;
				}

				base.OnAnchorChanged(new ValueChangeEventArgs( oldValue, value));

			}
		}



		[DefaultValue(typeof(Size),"-2147483648,-2147483648")]
		[Browsable( false)]
		public override Size MinSize
		{
			get
			{
				return base.MinSize;
			}
			set
			{
				base.MinSize = value;
			}
		}



		protected override void Dispose(bool disposing)
		{
			Delegate.RemoveAll(PointsChanged,PointsChanged);PointsChanged = null;
			base.Dispose (disposing);
		}


		private bool _boundsChanging = false;



		protected override void OnBoundsChanged(ValueChangeEventArgs eventArg)
		{

			if( _boundsChanging ) return;

			Rectangle oldBounds = Rectangle.Round( (RectangleF)eventArg.OldValue );
			Rectangle newBounds = Rectangle.Round( (RectangleF)eventArg.NewValue);

			//RecalculatePoints(oldBounds, newBounds, true);
			
			//NEW------------------------------------------------------------
			if( oldBounds.Location != newBounds.Location ) 
			{
				Rectangle b = RecalculatePoints(oldBounds, newBounds, true);

				if( newBounds != b )
				{
					SetBounds( b, false );
					eventArg.SetValues( oldBounds, b ); 
				}
			}
			//---------------------------------------------------------------
			base.OnBoundsChanged (eventArg);


		}

		protected internal Rectangle RecalculatePoints( Rectangle oldBounds, Rectangle newBounds  )//Otherwise size
		{//Called externally by parent(ShapeContainer)

			Rectangle b = RecalculatePoints(oldBounds, newBounds,false);
			if( newBounds != b ) SetBounds( b, false);
			this.ResetPath();
			return b;


//			if( oldBounds == newBounds ) return Rectangle.Round( this.Bounds );
//
//			try
//			{
//				_boundsChanging  = true;
//
//				Rectangle bb = RecalculatePoints(oldBounds, newBounds, false);
//			
//				if( this.Bounds != bb ) SetBounds( bb, true );
//				this.ResetPath();
//			
//				return Rectangle.Round( this.Bounds );
//			}
//			finally
//			{
//				_boundsChanging  = false;
//			}

		}



		private Rectangle RecalculatePoints( Rectangle oldBounds, Rectangle newBounds , bool locationOnly )//Otherwise size
		{

			Point p1 = oldBounds.Location;
			Point p2 = newBounds.Location ;
			int dx = p2.X - p1.X;
			int dy = p2.Y - p1.Y;

			int sdx =  newBounds.Right - oldBounds.Right;
			int sdy =  newBounds.Bottom - oldBounds.Bottom ;

			if( locationOnly )
			{
				sdx = 0;
				sdy = 0;
			}
		

			AnchorPoint[] pts = _pathPoints ;
			bool anyChanged = false;

			for( int i = 0; i < pts.Length; i++)
			{
				AnchorPoint pt = pts[i];
				AnchorStyles anchor = pt.Anchor;


				if( locationOnly )
				{
					pt.X += dx;	
					pt.Y += dy;
				}
				else
				{
					if((anchor & AnchorStyles.Left) > 0) pt.X += dx;	
					if((anchor & AnchorStyles.Top ) > 0) pt.Y += dy;
				}

				if( (anchor & AnchorStyles.Right  ) > 0) pt.X += sdx;	
				if( (anchor & AnchorStyles.Bottom ) > 0) pt.Y += sdy;

				if( pts[i] != pt ) anyChanged = true;
 				pts[i] = pt;
			}

			if( anyChanged ) OnPointsChanged( new EventArgs());

			return RectangleUtil.GetBounds( ToPoints( ));

		}




		protected virtual void OnPointsChanged( EventArgs eventArg )
		{
			if( this.PointsChanged != null) this.PointsChanged( this, eventArg );
		}

		protected override GraphicsPath MakePath(RectangleF bounds)
		{
			return MakePath( this.ToPoints() , _closed );
		}


		protected abstract GraphicsPath MakePath(Point[] points, bool closed );

		
		protected AnchorPoint[] GetPoints()
		{
			return _pathPoints;
		}

		protected virtual bool ValidatePoints( AnchorPoint[] points )
		{
			return true;
		}


		
		protected void SetPoints(AnchorPoint[] points)
		{
			if( !this.ValidatePoints( points) ) return;
 
			AnchorPoint[] oldPoints = _pathPoints;
			_pathPoints = points;

			//new
			Rectangle b = RectangleUtil.GetBounds( ToPoints( ));
			SetBounds( b, true );
			OnPointsChanged( new EventArgs());
			ResetPath();
		}


	

		[DesignOnly( true)]
		protected virtual bool ShouldSerializePoints()
		{
			return _pathPoints != null && _pathPoints.Length > 0;
		}


		public static Point[] ToPoints(AnchorPoint[] anchorPoints)
		{
			if( anchorPoints == null) return null;

			Point[] points = new Point[anchorPoints.Length];
			for(int i = 0; i < anchorPoints.Length; i++) points[i] = anchorPoints[i];

			return points;
		}

		public Point[] ToPoints()
		{
			return ToPoints( _pathPoints );
		}


		private AnchorPoint[] _pathPoints =new AnchorPoint[]{ };
		[Browsable(true)]
		[Category("Layout")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		public virtual AnchorPoint[] Points
		{
			get
			{
				if( _pathPoints == null) return new AnchorPoint[]{};
				return _pathPoints.Clone() as AnchorPoint[];
			}

			set
			{
				if( value == null ) value = new AnchorPoint[]{};
				
				if( !ValidatePoints( value )) return;

				//FileWatcher.WriteLine("VectorShape::Anchor points changed");
				if( value.Length > 1)
				{
					RectangleF bounds = RectangleUtil.GetBounds( ToPoints( value ));
					SetBounds( bounds, true );
				}

				AnchorPoint[] oldPoins = _pathPoints;
				_pathPoints = value;
				OnPointsChanged( new EventArgs());
				ResetPath();
			}
		}

		
		private bool _closed = false;
		[Category("Style")]
		[DefaultValue(false)]
		public bool Closed
		{	
			get{ return _closed;}
			set
			{
				if( value == _closed) return;
				_closed = value;
				InvokeInternalChanged( true );
			}

		}

		public int[] ContainingIndices( RectangleF rectangle, bool transfromPoints)
		{
			
			Point[] pts = this.ToPoints();

			if( transfromPoints )
			{
				Matrix m = base.Matrix;
				if( m != null && m.IsIdentity) m.TransformPoints( pts );
			}

			ArrayList list = new ArrayList();

			for ( int i =0; i < pts.Length; i++)
				if( rectangle.Contains( pts[i])) list.Add( i );
			return list.ToArray( typeof( int[]))  as int[];

		}

		public int Find( AnchorPoint point )
		{
			for ( int i =0; i < _pathPoints.Length; i++)
			if( _pathPoints[i] == point) return i;
			
			return -1;
		}

	}
}
